package bancosys.tec.persist.authorization;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

import org.apache.commons.beanutils.PropertyUtils;

import bancosys.tec.persist.Persistable;
import bancosys.tec.persist.authorization.annotation.DisplayName;

/**
 * @created 03/01/2008
 * @author Gustavo Almeida
 */
public final class DisplayNameUtil {
    private static final String GET_PREFIX = "get";

    private static final int GET_PREFIX_SIZE = GET_PREFIX.length();

    private static final String IS_PREFIX = "is";

    private static final int IS_PREFIX_SIZE = IS_PREFIX.length();

    /**
     * Construtor privado.
     */
    private DisplayNameUtil() {
        super();
    }

    /**
     * Devolve o nome para interface de usuario do bean persistível ou <code>null</code> caso o bean não possua DisplayName.
     * 
     * @param type classe do bean
     * @return nome
     */
    public static String getBeanStrictDisplayName(Class<? extends Persistable> type) {
        DisplayName displayName = type.getAnnotation(DisplayName.class);
        if (displayName != null) {
            return displayName.value();
        }
        return null;
    }

    /**
     * Devolve o nome para interface de usuario do bean persistível.
     * 
     * @param type classe do bean
     * @return nome
     */
    public static String getBeanDisplayName(Class<? extends Persistable> type) {
        String displayName = getBeanStrictDisplayName(type);
        if (displayName != null) {
            return displayName;
        } else {
            return type.getName();
        }
    }

    /**
     * Devolve o nome para interface de usuario da property bean persistível, devolve <code>null</code> se a property não existir ou
     * <code>null</code> caso o bean não possua DisplayName.
     * 
     * @param type classe do bean.
     * @param property property.
     * @return nome da property.
     */
    public static String getBeanStrictPropertyDisplayName(Class<?> type, String property) {
        for (PropertyDescriptor propertyDescriptor : PropertyUtils.getPropertyDescriptors(type)) {
            if (propertyDescriptor.getName().equals(property)) {
                Method readMethod = PropertyUtils.getReadMethod(propertyDescriptor);
                if (readMethod != null) {
                    return getBeanStrictPropertyDisplayName(readMethod);
                } else {
                    return null;
                }
            }
        }
        return null;
    }

    /**
     * Devolve o nome para interface de usuario da property bean persistível, devolve <code>null</code> se a property não existir.
     * 
     * @param type classe do bean.
     * @param property property.
     * @return nome da property.
     */
    public static String getBeanPropertyDisplayName(Class<? extends Persistable> type, String property) {
        for (PropertyDescriptor propertyDescriptor : PropertyUtils.getPropertyDescriptors(type)) {
            if (propertyDescriptor.getName().equals(property)) {
                Method readMethod = PropertyUtils.getReadMethod(propertyDescriptor);
                if (readMethod != null) {
                    return getBeanPropertyDisplayName(readMethod);
                } else {
                    return null;
                }
            }
        }
        return null;
    }

    /**
     * Devolve o nome para interface de usuario da property bean persistível ou <code>null</code> caso o bean não possua DisplayName.
     * 
     * @param readMethod getter da property.
     * @return nome da property.
     */
    public static String getBeanStrictPropertyDisplayName(Method readMethod) {
        DisplayName displayName = readMethod.getAnnotation(DisplayName.class);
        if (displayName != null) {
            return displayName.value();
        }
        return null;
    }

    /**
     * Devolve o nome para interface de usuario da property bean persistível.
     * 
     * @param readMethod getter da property.
     * @return nome da property.
     */
    public static String getBeanPropertyDisplayName(Method readMethod) {
        String displayName = getBeanStrictPropertyDisplayName(readMethod);
        if (displayName != null) {
            return displayName;
        } else {
            String methodName = readMethod.getName();
            if (methodName.length() > GET_PREFIX_SIZE && methodName.startsWith(GET_PREFIX)) {
                char[] chars = methodName.substring(GET_PREFIX_SIZE).toCharArray();
                chars[0] = Character.toLowerCase(chars[0]);
                return String.copyValueOf(chars);
            }
            if (methodName.length() > IS_PREFIX_SIZE && methodName.startsWith(IS_PREFIX)) {
                char[] chars = methodName.substring(IS_PREFIX_SIZE).toCharArray();
                chars[0] = Character.toLowerCase(chars[0]);
                return String.copyValueOf(chars);
            }
            return methodName;
        }
    }
}
